package jmcnet.libcommun.jmcnetds.flex
{
	import flash.utils.getQualifiedClassName;
	
	import jmcnet.libcommun.communs.JMCNetLibCommunHelper;
	import jmcnet.libcommun.logger.JMCNetLog4JLogger;
	import jmcnet.libcommun.security.BaseLoginWindow;
	import jmcnet.libcommun.security.BaseSessionManager;
	
	import mx.managers.PopUpManager;
	import mx.rpc.AbstractOperation;
	import mx.rpc.AsyncToken;
	import mx.rpc.IResponder;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.RemoteObject;
	
	/**
	 * Un delegate de base permettant de s'interfacer avec BlazeDS
	 */
	public class BaseBlazeDSDelegate implements IResponder
	{
		private static var log:JMCNetLog4JLogger = new JMCNetLog4JLogger(getQualifiedClassName(BaseBlazeDSDelegate)); 
		private var _command : BaseCommand = null;
		
		// Variable pour pouvoir rappeler le service en erreur a cause d'une demande de login (pour rappel après login successfull)
		private var _remoteObject:RemoteObject = null;
		private var _methodName:String = null;
		private var _args:Array = null;
		
		/**
		 * Classe de base de tous les Delegate. Formalise les callbacks
		 */
		public function BaseBlazeDSDelegate(command : BaseCommand) {
			super();
			if ( getQualifiedClassName(super) == "BaseBlazeDSDelegate" )
            	throw new UninitializedError("La classe BaseBlazeDSDelegate est abstraite et ne peut pas être instanciée"); 
			_command = command;
		}
		
		public function get command():BaseCommand { return _command;}
		
		/**
		 * Appelée lors du retour de l'appel de service
		 */
		 public function result(obj:Object):void {
			log.info("Appel result OK");
			var retour:Object=obj.result;
			var ret:Boolean = _command.onResult(retour);
			this.callback(ret, retour);
			log.info("Fin result OK");
		}
		
		/**
		 * Appelée lors du retour du login OK
		 */
		 public function resultLogin(obj:Object):void {
			log.info("Appel resultLogin obj="+obj);
			// On rappelle la method
			if (_args != null && _args.length > 0) {
				callService(_remoteObject, _methodName, _args);
			}
			else callService(_remoteObject, _methodName);
			
			log.info("Fin resultLogin OK");
		}
		
		public function fault(info:Object):void	{
			log.warn("Appel fault erreur="+info.toString());
			var evt:FaultEvent = info as FaultEvent;
			// Si demande de login, on le fait
			switch (evt.fault.faultCode) {
				case "Client.Authentication" :
				// case "Server.Processing" : C'etait pour le logout qui ne marchait pas, mais plus la peine depuis que l'on fait logout 2 x 
					log.warn("Demande d'authentification");
					var loginWin:BaseLoginWindow = PopUpManager.createPopUp(JMCNetLibCommunHelper.mainAppDisplay,BaseSessionManager.loginWindowClass, true) as BaseLoginWindow;
					PopUpManager.centerPopUp(loginWin);
						
					// Pour que l'on soit rappeler lorsque le login est OK avec le resultat de l'appel du service
					loginWin.responderWhenOk = this.resultLogin;
					loginWin.responderWhenKo = this.fault;
					break;
				case "Channel.Call.Failed" :
					// Si l'erreur concerne le ChannelSet, on se deloggue, avant d'appeler onTechnicalError
					log.warn("Erreur sur le ChannelSet, on se deloggue");
					BaseSessionManager.sessionManager.closeSession();
					// Il n'y a pas de break, et c'est fait exprès pour qu'on appelle onTechnicalError
					// break;
				default :
					_command.onTechnicalError(new Error(info.toString()), null);
					this.callback(false, info);
					break;
			}
			log.warn("Fin fault OK");
		}
		
		protected function callback(ok:Boolean, data:Object):void {
			if (_command.event != null) {
				_command.event.callback(ok, data);
			}
		}
		
		protected function callService(service:RemoteObject, methodName:String, ... args:Array):void {
			log.info("Appel callService service="+service+" methodName='"+methodName+"' args.length="+args.length+" args="+args);

			_remoteObject = service;
			_methodName = methodName;
			_args = args;
			
			log.debug("args.length="+args.length+" _args.length="+_args.length);
						
			var operation:AbstractOperation = service.getOperation(methodName);
			
//			JMCNetLogger.debug("Suppression et recreation des eventListener précédents");
//			try {
//				while (operation.hasEventListener(ResultEvent.RESULT)) {
//					JMCNetLogger.debug("Suppression eventListener RESULT précédents");
//					operation.removeEventListener(ResultEvent.RESULT,result);
//				}
//				while (operation.hasEventListener(FaultEvent.FAULT)) {
//					JMCNetLogger.debug("Suppression eventListener FAULT précédents");
//					operation.removeEventListener(FaultEvent.FAULT, fault);
//				}
//			} catch (err:*) {
//				JMCNetLogger.error("Erreur pendant suppression des eventListener précédents : "+err);
//			}
			
			/* if (!operation.hasEventListener(ResultEvent.RESULT)) operation.addEventListener(ResultEvent.RESULT,result);
			if (!operation.hasEventListener(FaultEvent.FAULT)) operation.addEventListener(FaultEvent.FAULT, fault);
			*/
			
			operation.arguments = args;
			var token:AsyncToken = operation.send();
			token.addResponder(this);
			// token.addEventListener(FaultEvent.FAULT, fault);
			log.info("Fin callService '"+methodName+"' OK");
		}
	}
}